/*
 * Hardware.cpp
 *
 * Provides a simple access point for all the hardware connected
 * If we connect more hardware to the device we need to add access methods here.
 *
 *  Created on: 22/05/2013
 *      Author: roger
 */

#include "Hardware.h"


Adafruit_TFTLCD Graphics(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, its 371 ohms across the X plate
// measured again on 13/08/14 it floats around a bit but say 85
TouchScreen Touchscreen = TouchScreen(XP, YP, XM, YM, 80);


Hardware_::Hardware_() {
	m_lsm303 = LSM303();
	// Calibration values. Use the Calibrate example program to get the values for
	// your compass.
	m_lsm303.m_min.x = -880;
	m_lsm303.m_min.y = -691;
	m_lsm303.m_min.z = -958;
	m_lsm303.m_max.x = +262;
	m_lsm303.m_max.y = +365;
	m_lsm303.m_max.z = -27;
}
/*
 * Put us into hibernate mode. Need to press the restart button to come out of this.
 */
void Hardware_::shutdown() {
	Graphics.setRotation(3);
	Graphics.fillScreen(BLACK);
	Graphics.setTextSize(2);
	Graphics.setCursor(80,Graphics.height()/2);
	Graphics.print(PSTR("sleeping..."));
	delay(1000);
	Graphics.fillScreen(BLACK);
	heartRateInterrupt.setLogRawData(false);
#ifdef HARDWARE_DEBUG
	Serial.println(PSTR("sleeping...."));
#endif
	digitalWrite(BACKLIGHT, LOW);
	digitalWrite(POWER_PIN, LOW);
	digitalWrite(CTS, LOW);
	pinMode(11, INPUT_PULLUP);
	m_lowPower.DeepSleep(GPIO_WAKE, PIN_11);
	// We get here when we wake up
	digitalWrite(BACKLIGHT, HIGH);
	digitalWrite(POWER_PIN, HIGH);
	digitalWrite(CTS, HIGH);
	blink0();
	blink1();
	Graphics.reset();
	uint16_t identifier = Graphics.readID();
	Graphics.begin(identifier);
#ifdef HARDWARE_DEBUG
	Serial.begin(9600);
	Serial.println(PSTR("waking...."));
#endif
	setSyncProvider((getExternalTime)Teensy3Clock.get); // resync the clock when we wake up
}

void Hardware_::init()
{
#ifdef HARDWARE_DEBUG
	Serial.println(INIT);
#endif
	pinMode(SD_CS, OUTPUT);
	pinMode(LED0_PIN, OUTPUT);
	pinMode(LED1_PIN, OUTPUT);
	pinMode(BACKLIGHT, OUTPUT);
	pinMode(POWER_PIN, OUTPUT);
	pinMode(CTS,OUTPUT);
	digitalWrite(POWER_PIN, HIGH);
	digitalWrite(BACKLIGHT, HIGH);
	digitalWrite(CTS, HIGH);
	Wire.begin();
	if (!SD.begin(SD_CS)) {
		Serial.println(PSTR("SD initialization failed!"));
	} else {
		m_sdOK = true;
		Serial.println(PSTR("SD initialization done."));
		dumpSD(PSTR("after SD init"));
	}

	m_lsm303.init();
	m_lsm303.enableDefault();
	compass(false);

	Graphics.reset();
	uint16_t identifier = Graphics.readID();

	if (identifier == 0x9325) {
		progmemPrintln(PSTR("Found ILI9325 LCD driver"));
	} else if (identifier == 0x9328) {
		progmemPrintln(PSTR("Found ILI9328 LCD driver"));
	} else if (identifier == 0x7575) {
		progmemPrintln(PSTR("Found HX8347G LCD driver"));
	} else {
		progmemPrint(PSTR("Unknown LCD driver chip: "));
		Serial.println(identifier, HEX);
		progmemPrintln(
				PSTR("If using the Adafruit 2.8\" TFT Arduino shield, the line:"));
		progmemPrintln(PSTR("  #define USE_ADAFRUIT_SHIELD_PINOUT"));
		progmemPrintln(
				PSTR("should appear in the library header (Adafruit_TFT.h)."));
		progmemPrintln(
				PSTR("If using the breakout board, it should NOT be #defined!"));
		progmemPrintln(
				PSTR("Also if using the breakout, double-check that all wiring"));
		progmemPrintln(PSTR("matches the tutorial."));
		return;
	}

	Graphics.begin(identifier);
	Graphics.fillScreen(BLACK);
	m_lowPower = TEENSY3_LP();

#ifdef HARDWARE_DEBUG
	Serial.print(PSTR("tft done...."));
	Serial.println(identifier, HEX);
#endif
}
void Hardware_::playTone(uint16_t frequency, uint32_t duration, uint32_t delay_after) {
#ifdef HARDWARE_DEBUG
	Serial.println(PSTR("tone"));
#endif
	tone(TONE_PIN, frequency,duration);
	delay(delay_after);
	noTone(TONE_PIN);
}
void Hardware_::siren() {
#ifdef HARDWARE_DEBUG
	Serial.println(PSTR("siren"));
#endif
	for (int i=0;i<10;i++) {
		tone(TONE_PIN, 3136+(i*10),10);
		delay(10);
	}
	noTone(TONE_PIN);
}
float Hardware_::getBatteryVoltage() {
//#ifdef HARDWARE_DEBUG
//	Serial.print("Raw voltage ");
//	Serial.println(analogRead(VOLTAGE_PIN));
//#endif
	return 0.095526316*analogRead(VOLTAGE_PIN);
}

int Hardware_::readInt(File dataFile)
{
	String v = "";
	char t = dataFile.read();
	while (t != ',' && t != -1)
	{
		v.append(t);
		t = dataFile.read();
	}
	return v.toInt();
}
int Hardware_::compassHeading()
{
	m_lsm303.read();
	return m_lsm303.heading((LSM303::vector) {0,-1,0});
}
void Hardware_::compass(bool start)
{
#ifdef HARDWARE_DEBUG
	Serial.println(PSTR("compass(bool start)..."));
#endif
	if (start) {
		m_lsm303.enableDefault();
	} else {
		m_lsm303.writeMagReg(LSM303_MR_REG_M, 0x03);
	}
#ifdef HARDWARE_DEBUG
	Serial.println(PSTR("compass(bool start) done"));
#endif
}
LSM303::vector Hardware_::getAccelerometerValues() {
#ifdef HARDWARE_DEBUG
	Serial.println(PSTR("getAccelerometerValues()..."));
#endif
	m_lsm303.read();
#ifdef HARDWARE_DEBUG
	Serial.println(PSTR("getAccelerometerValues() done"));
#endif
	return m_lsm303.a;
}

void Hardware_::printDirectory(File dir, int numTabs) {
	dir.rewindDirectory();
	while (true) {

		File entry = dir.openNextFile();
		if (!entry) {
			// no more files
			//Serial.println("**nomorefiles**");
			break;
		}
		for (uint8_t i = 0; i < numTabs; i++) {
			Serial.print('\t');
		}
		Serial.print(entry.name());
		if (entry.isDirectory()) {
			Serial.println("/");
			printDirectory(entry, numTabs + 1);
		} else {
			// files have sizes, directories do not
			Serial.print("\t\t");
			Serial.println(entry.size(), DEC);
		}
		entry.close();
	}
}

Hardware_::~Hardware_() {
	// TODO Auto-generated destructor stub
}
// Copy string from flash to serial port
// Source string MUST be inside a PSTR() declaration!
void Hardware_::progmemPrint(const char *str) {
	char c;
	while ((c = pgm_read_byte(str++)))
		Serial.print(c);
}

// Same as above, with trailing newline
void Hardware_::progmemPrintln(const char *str) {
	progmemPrint(str);
	Serial.println();
}

//void Hardware_::drawIcon(const int x, const int y, const Icon *icon) {
//	drawIcon(icon->size,x,y,(const char *)icon->bitmap);
//}
//void Hardware_::drawIcon(const unsigned int size,const int x, const int y, const char *pImg) {
//	char pRGB[3];
//	for (unsigned int j = 0; j < size; j++)
//	for (unsigned int i = 0; i < size; i++)
//	{
//		HEADER_PIXEL(pImg, pRGB)
//		uint16_t colour = ((unsigned long)pRGB[0])+
//				(((unsigned long)pRGB[1])<<8)+
//				(((unsigned long)pRGB[2])<<16);
//		Graphics.drawPixel(x+i,y+j, colour);
//	}
//}
const char *Hardware_::timeString(long adjustedDate) {
	sprintf(dstring, PSTR("%02d:%02d:%02d"),hour(adjustedDate),minute(adjustedDate),second(adjustedDate));
	return dstring;
}
const char *Hardware_::dateString(long adjustedDate) {
	sprintf(dstring, PSTR("%04d-%02d-%02d"),year(adjustedDate),month(adjustedDate),day(adjustedDate));
	return dstring;
}
// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.

uint16_t Hardware_::read16(File f) {
  uint16_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read(); // MSB
  return result;
}

uint32_t Hardware_::read32(File f) {
  uint32_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read();
  ((uint8_t *)&result)[2] = f.read();
  ((uint8_t *)&result)[3] = f.read(); // MSB
  return result;
}

HeartRateInterrupt heartRateInterrupt = HeartRateInterrupt(now());

Hardware_ Hardware = Hardware_();
